<?php
/*
 *  Copyright (c) 2024 Borlabs GmbH. All rights reserved.
 *  This file may not be redistributed in whole or significant part.
 *  Content of this file is protected by international copyright laws.
 *
 *  ----------------- Borlabs Cookie IS NOT FREE SOFTWARE -----------------
 *
 *  @copyright Borlabs GmbH, https://borlabs.io
 */

declare(strict_types=1);

namespace Borlabs\Cookie\Support\Traits;

use ReflectionClass;
use ReflectionException;

trait ReflectionTrait
{
    /**
     * Caches the reflections of enum classes.
     *
     * @var array<ReflectionClass>
     */
    private static $reflectionCache = [];

    /**
     * Get list of all enum values.
     */
    private static function getConstants(): array
    {
        return self::getReflection()->getConstants();
    }

    /**
     * Returns a ReflectionClass instance of the parent class if a parent class exists, otherwise returns null.
     */
    private static function getParentClass(string $class): ?ReflectionClass
    {
        $parentClass = self::getReflection($class)->getParentClass();

        return $parentClass !== false ? $parentClass : null;
    }

    /**
     * Get list of properties.
     */
    private static function getProperties(): array
    {
        return self::getReflection()->getProperties();
    }

    /**
     * Returns the ReflectionClass for the late bound class.
     *
     * @throws ReflectionException
     */
    private static function getReflection(?string $class = null): ReflectionClass
    {
        $class = $class ?? static::class;

        return self::$reflectionCache[$class] ??= new ReflectionClass($class);
    }

    /**
     * Check if the constant exists.
     */
    private static function hasConstant(string $constantName): bool
    {
        return self::getReflection()->hasConstant($constantName);
    }

    /**
     * Check if the method exists.
     */
    private static function hasMethod(string $methodName): bool
    {
        return self::getReflection()->hasMethod($methodName);
    }

    /**
     * Check if the class is a Dto class.
     */
    private static function isDto(string $class): bool
    {
        $parentClass = self::getParentClass($class);

        if ($parentClass === null) {
            return false;
        }

        return strstr($parentClass->getName(), '\Dto\AbstractDto') !== false;
    }

    /**
     * Check if the class is a AbstractDtoList class.
     */
    private static function isDtoList(string $class): bool
    {
        $parentClass = self::getParentClass($class);

        if ($parentClass === null) {
            return false;
        }

        return strstr($parentClass->getName(), '\DtoList\AbstractDtoList') !== false;
    }

    /**
     * Check if the class is a AbstractEnum class.
     */
    private static function isEnum(string $class): bool
    {
        $parentClass = self::getParentClass($class);

        if ($parentClass === null) {
            return false;
        }

        return strstr($parentClass->getName(), '\Enum\AbstractEnum') !== false;
    }
}
